#ifndef PRVP_PROBLEMINSTANCE_HPP_
#define PRVP_PROBLEMINSTANCE_HPP_

#include <iostream>

#include "../OptFrame/Util/Scanner++/Scanner.h"

using namespace std;

class PRVPProblemInstance
{

public:

	Matrix<double>* dist; //custo de transporte
	vector<vector<int> >* dados; //dados extras do problema
	int id, nVeic, nCli, nPeriod, capacidade, duracaoMax;
	bool prv;

	//variaveis dinamicamente atualizadas
	vector<vector<int> > *periodsCli;
	vector<int> *escolhas;

	PRVPProblemInstance(Scanner& instancia)
	{

		//identificador da instância
		id = instancia.nextChar();
		//número de veículos
		nVeic = instancia.nextInt();
		//número de clientes
		nCli = instancia.nextInt();
		//número de periodos
		nPeriod = instancia.nextInt();

		//matriz de coordenadas
		Matrix<double> coordenadas(nCli + 1, 2); // +1 para contar o depósito
		//matriz de distancias
		dist = new Matrix<double> (nCli + 1); // +1 para contar o depósito

		/*
		 Dados extras
		 */
		dados = new vector<vector<int> > (nCli + 1);// +1 para contar o depósito

		for (int i = 0; i < nPeriod; ++i) // duração da rota e capacidade de veículos igual para todos os periodos
		{
			duracaoMax = instancia.nextInt();
			capacidade = instancia.nextInt();
		}

		//variavel que verificará se o problema pode ser reduzido ao PRV
		prv = true;
		int freq;

		for (int i = 0; i <= nCli; ++i)
		{
			dados->at(i).push_back(instancia.nextInt());// id do cliente [0]
			coordenadas(i, 0) = instancia.nextDouble(); //coordenada X
			coordenadas(i, 1) = instancia.nextDouble(); //coordenada Y
			dados->at(i).push_back(instancia.nextInt()); //duração do serviço[1]
			dados->at(i).push_back(instancia.nextInt()); // demanda [2]
			freq = instancia.nextInt();
			if(freq != 1 && i != 0)
			{
				prv = false;
			}
			dados->at(i).push_back(freq); //frequencia de visita [3]
			dados->at(i).push_back(instancia.nextInt()); //numero de combinações de visita possíveis [4]
			for (int j = 0; j < dados->at(i).at(NCOMB); ++j) //for de acordo com o numero de combinaçoes
			{
				dados->at(i).push_back(instancia.nextInt());
			}
		}

		if(prv)//caso a instacia possa ser reduzida para o PRV
		{
			/*cout<<"ALTERANDO PARA PRV"<<endl;
			getchar();*/
			//atualizando o número de combinações de visita
			for (int i = 0; i <= nCli; ++i)
			{
				dados->at(i).at(NCOMB) = 1;
			}
			//alterando o número de veículos
			nVeic = nVeic * nPeriod;
			nPeriod = 1;
		}

		instancia.close();

		// **************** calculando matriz de distâncias *******************
		for (int i = 0; i <= nCli; ++i)
		{
			for (int j = 0; j <= nCli; ++j)
			{
				(*dist)(i, j) = sqrt(pow(coordenadas(j, 0) - coordenadas(i, 0), 2) + pow(coordenadas(j, 1) - coordenadas(i, 1), 2));
			}
		}

		//definindo o tamanho de escolha e periodosCli
		escolhas = new vector<int> (nCli + 1);
		periodsCli = new vector<vector<int> > (nCli + 1);

	}

	~PRVPProblemInstance()
	{
		delete dist;
		delete dados;
		delete escolhas;
		delete periodsCli;
	}

	static vector<int> decompoeEscolha(int escolha, int n_periodos)
	{
		vector<int> periodos;
		int p = n_periodos - 1;
		while (escolha != 0)
		{
			if (escolha % 2 == 1)
			{
				periodos.push_back(p);
			}
			escolha = escolha / 2;
			p--; //passando para o proximo periodo
		}

		return periodos;
	}

	bool chech_solution(SolutionPRVP& s)
	{
		bool ok = true;

		RepPRVP& rep = s.getR();
		for (int c = 1; c <= nCli; c++)
		{
			int numOccor = 0;
			for (int p = 0; p < rep.size(); ++p)
			{
				for (int r = 0; r < rep.at(p).size(); r++)
				{
					for (int pos = 0; pos < rep.at(p).at(r).size(); pos++)
					{
						if(c == rep.at(p).at(r).at(pos))
							numOccor++;
					}
				}
			}
			if(numOccor != 1)
			{
				cout<<"cliente errado: "<<c<<" \t numOccor: "<<numOccor<<endl;
				return false;
			}
		}
		return ok;
	}

};

#endif /*PRVP_PROBLEMINSTANCE_HPP_*/

